package com.xhh.microfin.dispatch.service.process.impl;

import com.xhh.microfin.dispatch.common.utils.DateTimeUtil;
import com.xhh.microfin.dispatch.exception.ProcessNodeNotFoundException;
import com.xhh.microfin.dispatch.exception.ProcessNotFoundException;
import com.xhh.microfin.dispatch.model.consts.ProcessConsts;
import com.xhh.microfin.dispatch.model.entity.*;
import com.xhh.microfin.dispatch.model.entity.Process;
import com.xhh.microfin.dispatch.model.enums.ProcessStatusEnum;
import com.xhh.microfin.dispatch.model.mapper.ProcessInstanceMapper;
import com.xhh.microfin.dispatch.model.mapper.ProcessNodeMapper;
import com.xhh.microfin.dispatch.model.mapper.ProcessVarMapper;
import com.xhh.microfin.dispatch.model.mapper.TaskVarMapper;
import com.xhh.microfin.dispatch.model.mapper.extend.*;
import com.xhh.microfin.dispatch.service.process.IProcess;
import com.xhh.microfin.dispatch.service.process.ITask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Author: 003035
 * @Date: 2019/1/16
 */
@Service
public class ProcessImpl implements IProcess {

    @Autowired
    private ProcessInstanceExtendMapper processInstanceExtendMapper;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private ProcessExtendMapper processExtendMapper;

    @Autowired
    private ProcessInstanceMapper processInstanceMapper;

    @Autowired
    private ProcessNodeExtendMapper processNodeExtendMapper;

    @Autowired
    private TaskExtendMapper taskExtendMapper;

    @Autowired
    private ProcessNodeMapper processNodeMapper;

    @Autowired
    private ProcessVarExtendMapper processVarExtendMapper;

    @Autowired
    private TaskVarExtendMapper taskVarExtendMapper;

    @Autowired
    private ProcessVarMapper processVarMapper;

    @Autowired
    private TaskVarMapper taskVarMapper;

    @Override
    public ProcessInstance startProcess(String procssCode,String businessId) {

        // find process
        Process process = processExtendMapper.selectByProcessCode(procssCode);
        if (null == process) {
            throw new ProcessNotFoundException();
        }

        // add process instance
        ProcessInstance processInstance = new ProcessInstance();
        processInstance.setProcessId(process.getId());
        processInstance.setStatus(ProcessStatusEnum.ACTIVE.getCode());
        processInstance.setBusinessId(businessId);
        processInstanceMapper.insert(processInstance);

        // get start node
        ProcessNode processNode = processNodeExtendMapper.selectStartNodeByProcessId(process.getId());

        // active node
        ITask iTask = applicationContext.getBean(processNode.getCode(), ITask.class);
        Task begin = iTask.begin(processNode,processInstance.getId());

        return processInstance;
    }

    @Override
    public ProcessInstance process(ProcessInstance processInstance) {

        List<Task> tasks = taskExtendMapper.selectActiveTaskByProcessInstanceId(processInstance.getId());
        tasks.forEach(task -> {
            ProcessNode processNode = processNodeMapper.selectByPrimaryKey(task.getNodeId());
            if (null == processNode) {
                throw new ProcessNodeNotFoundException();
            }
            ITask iTask = applicationContext.getBean(processNode.getCode(), ITask.class);
            iTask.process(task);
        });
        return processInstance;
    }

    @Override
    public List<Var> getProcessVar(Integer processId) {

        Map<String, String> map = new HashMap<>();
        List<ProcessVar> processVars = processVarExtendMapper.selectByProcessId(processId);
        return Var.getVarFromProcessVar(processVars);
    }

    @Override
    public List<Var> getTaskVar(Integer taskId) {

        Map<String, String> map = new HashMap<>();
        List<TaskVar> taskVars = taskVarExtendMapper.selectByTaskId(taskId);
        return Var.getVarFromTaskVar(taskVars);
    }

    @Override
    public ProcessInstance getProcessInstanceByBusId(String businessId) {

        ProcessInstance processInstance = processInstanceExtendMapper.selectByBusinessId(businessId);
        return processInstance;
    }

    @Override
    public ProcessContext prepareProcessContext(Task task) {

        ProcessContext processContext = new ProcessContext();
        processContext.setProcessInstanceId(task.getProcessInstanceId());
        ProcessInstance processInstance = processInstanceMapper.selectByPrimaryKey(task.getProcessInstanceId());
        processContext.setBusinessId(processInstance.getBusinessId());
        processContext.setCurrentTaskId(task.getId());

        List<Var> processVar = getProcessVar(task.getProcessInstanceId());
        List<Var> taskVar = getTaskVar(task.getId());
        processContext.addAll(processVar);
        processContext.addAll(taskVar);
        return processContext;
    }

    @Override
    public boolean addProcessVar(ProcessContext context, Var var) {

        context.add(var);
        ProcessVar processVar = new ProcessVar();
        processVar.setVarCode(var.getVarCode());
        processVar.setValue(var.getValue());
        processVar.setProcessInstanceId(context.getProcessInstanceId());
        processVarMapper.insert(processVar);
        return true;
    }

    @Override
    public boolean addTaskVar(ProcessContext context, Var var) {

        context.add(var);
        TaskVar taskVar = new TaskVar();
        taskVar.setVarCode(var.getVarCode());
        taskVar.setValue(var.getValue());
        taskVar.setCtime(var.getCtime());
        taskVar.setTaskId(context.getCurrentTaskId());
        taskVar.setMtime(DateTimeUtil.getNowSeconds());
        taskVarMapper.insert(taskVar);
        return true;
    }

    @Override
    public boolean addTaskVar(Task task, Var var) {

        TaskVar taskVar = new TaskVar();
        taskVar.setTaskId(task.getId());
        taskVar.setCtime(var.getCtime());
        taskVar.setValue(var.getValue());
        taskVar.setVarCode(var.getVarCode());
        taskVar.setMtime(var.getCtime());
        taskVarMapper.insert(taskVar);
        return true;
    }

    @Override
    public List<Task> getTaskByProcessInstanceIdAndTaskCode(Integer processInstanceId, String taskCode) {

        Map<String, Object> param = new HashMap<>();
        param.put(ProcessConsts.PROCESS_INSTANCE_ID, processInstanceId);
        param.put(ProcessConsts.TASK_CODE, taskCode);
        List<Task> tasks = taskExtendMapper.basicQuery(param);
        return tasks;
    }


}
